home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload Trio 2
/
Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO
/
dir24
/
psi110g.zip
/
MAILBOX.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-06
|
42KB
|
1,521 lines
/* NOTE: because of size, the previous 'mailbox.c' and 'mailbox2.c'
* have been split in 5 parts:
* mboxcmd.c, containing the 'mbox' subcommands,
* mailbox.c, containing general mailbox user commands,
* mboxfile.c, containing file mailbox user commands,
* mboxmail.c, containing mail mailbox user commands, and
* mboxgate.c, containing gateway mailbox user commands.
* 940215 - WG7J
*/
/* There are only two functions in this mailbox code that depend on the
* underlying protocol, namely mbx_getname() and dochat(). All the other
* functions can hopefully be used without modification on other stream
* oriented protocols than AX.25 or NET/ROM.
*
* SM0RGV 890506, most work done previously by W9NK
*
*** Changed 900114 by KA9Q to use newline mapping features in stream socket
* interface code; everything here uses C eol convention (\n)
*
* Numerous new commands and other changes by SM0RGV, 900120
*
* Gateway function now support outgoing connects with the user's call
* with inverted ssid. Users can connect to system alias as well...
* See also several mods in socket.c,ax25.c and others
* 11/15/91, WG7J/PA3DIS
*
* Userlogging, RM,VM and KM commands, and R:-line interpretation
* added 920307 and later, Johan. K. Reinalda, WG7J/PA3DIS
*
* Inactivity timeout-disconnect added 920325 and later - WG7J
*
*/
#include <time.h>
#include <ctype.h>
#ifdef MSDOS
#include <alloc.h>
#endif
#ifdef UNIX
#include <sys/types.h>
#include <sys/stat.h>
#endif
#include "global.h"
#ifdef MAILBOX
#include "timer.h"
#include "proc.h"
#include "socket.h"
#include "usock.h"
#include "session.h"
#include "smtp.h"
#include "dirutil.h"
#include "telnet.h"
#include "ftp.h"
#include "ftpserv.h"
#include "commands.h"
#include "netuser.h"
#include "files.h"
#include "bm.h"
#include "pktdrvr.h"
#include "ax25.h"
#include "mailbox.h"
#include "ax25mail.h"
#include "nr4mail.h"
#include "cmdparse.h"
#include "mailfor.h"
#include "mailutil.h"
#include "index.h"
struct mbx *Mbox;
int BbsUsers;
int Totallogins;
extern int MbShowAliases;
#ifdef RLOGINSERVER
static char DFAR RLoginbanner[] = "\nRemote Login at %s - %s\n\n";
#endif
char Loginbanner[] = "\nJNOS (%s)\n\n";
char Mbwelcome[] = "\nWelcome %s,\n";
char Mbbanner[] = "to the %s TCP/IP Mailbox (JNOS %s).\n";
char CurUsers[] = "Currently %d user%s.\n";
#if defined MAILCMDS || defined FILECMDS
char Howtoend[] = "End with /EX or ^Z in first column (^A aborts):\n";
char MsgAborted[] = "Msg aborted\n";
#endif
#ifdef MAILCMDS
char MbCurrent[] = "Current msg# %d.\n";
#endif
char Mbmenu[] = "?,"
#ifdef MAILCMDS
"A,"
#endif
"ALI,"
"B,"
#ifdef GATECMDS
#if defined NETROM || defined AX25
"C,"
#endif
#endif
#ifdef CONVERS
"CONV,"
#endif
#ifdef FILECMDS
"D,"
#endif
#ifdef GATECMDS
"E,"
#endif
#ifdef FOQ_CMDS
"F,"
#endif
"H,I,IH,IP,J,"
#ifdef MAILCMDS
"K,L,"
#endif
"M,"
#if defined GATECMDS && defined NETROM
"N,NR,"
#endif
#if defined FOQ_CMDS && defined TTYLINKSERVER
"O,"
#endif
#ifdef GATECMDS
"P,PI,"
#endif
#if defined FOQ_CMDS && defined CALLCLI
"Q,"
#endif
#ifdef MAILCMDS
"R,S,"
#endif
#ifdef GATECMDS
"T,"
#endif
#ifdef FILECMDS
"U,"
#endif
#ifdef MAILCMDS
"V,"
#endif
#ifdef FILECMDS
"W,"
#endif
"X"
#ifdef FILECMDS
",Z"
#endif
" >\n";
extern char Mbnrid[];
/* This is called by the finger-daemon */
void
listusers(s)
int s;
{
int outsave;
struct mbx m;
m.privs = 0;
m.stype = ' ';
#ifdef notdef
usputs(s,"\nCurrent remote users:\n");
#endif
outsave = Curproc->output;
Curproc->output = s;
dombusers(0,NULLCHARP,&m);
Curproc->output = outsave;
}
struct mbx *
newmbx()
{
struct mbx *m,*new;
if((new = (struct mbx *) callocw(1,sizeof(struct mbx))) == NULLMBX)
return NULLMBX;
BbsUsers++;
/* add it the list */
if((m=Mbox) == NULLMBX)
Mbox = new;
else {
while(m->next)
m=m->next;
m->next = new;
}
return new;
}
static int
mbx_getname(m)
struct mbx *m;
{
char *cp;
#ifdef notdef
FILE *tfp;
#endif
union sp sp;
char tmp[MAXSOCKSIZE];
int len = MAXSOCKSIZE;
int anony = 0;
int oldmode;
int founddigit=0;
int count=0;
#ifdef AX25
int32 flags;
int ax_25 = 0;
struct usock *up;
#endif
sp.p = tmp;
sp.sa->sa_family = AF_LOCAL; /* default to AF_LOCAL */
getpeername(m->user,tmp,&len);
m->family = sp.sa->sa_family;
m->path = mallocw(MBXLINE);
/* This is one of the two parts of the mbox code that depends on the
* underlying protocol. We have to figure out the name of the
* calling station. This is only practical when AX.25 or NET/ROM is
* used. Telnet users have to identify themselves by a login procedure.
*/
switch(sp.sa->sa_family){
#ifdef AX25
case AF_AX25:
/* If this is not to the convers call, and this port is
* set for NO_AX25, then disconnect ! - WG7J
*/
if((m->type != CONF_LINK) && ((up = itop(m->user)) != NULLUSOCK) ) {
if((flags=up->cb.ax25->iface->flags) & NO_AX25)
return -1;
}
ax_25 = 1;
/* note fallthrough */
case AF_NETROM:
/* NETROM and AX25 socket address structures are "compatible" */
/* Save user call, in case user wants to use gateway function */
memcpy(m->call,sp.ax->ax25_addr,AXALEN);
m->call[ALEN] &= 0xfc;/*Make sure E-bit isn't set !*/
pax25(m->name,sp.ax->ax25_addr);
cp = strchr(m->name,'-');
if(cp != NULLCHAR) /* get rid of SSID */
*cp = '\0';
/* SMTP wants the name to be in lower case */
cp = m->name;
while(*cp){
if(isupper(*cp))
*cp = tolower(*cp);
++cp;
}
anony = 1;
/* Try to find the privileges of this user from the userfile */
if((m->privs = userlogin(m->name,m->line,&m->path,MBXLINE,
&anony,ax_25 ? "ax25def" : "netdef")) == -1){
m->privs = 0;
free(m->path);
m->path = NULLCHAR;
}
if(m->privs & EXCLUDED_CMD)
return -1;
if(ax_25)
if(((flags & USERS_ONLY) && (m->privs & IS_BBS)) ||
((flags & BBS_ONLY) && !(m->privs & IS_BBS)) ||
((flags & SYSOP_ONLY) && !(m->privs & SYSOP_CMD)))
return -1;
return 0;
#endif
case AF_LOCAL:
case AF_INET:
m->state = MBX_LOGIN;
#ifdef RLOGINSERVER
if(m->type == RLOGIN_LINK)
tprintf(RLoginbanner,Hostname,Version);
else {
#endif
tprintf(Loginbanner,Hostname);
if(Mtmsg != NULLCHAR)
tputs(Mtmsg);
#ifdef RLOGINSERVER
}
#endif
for(;;){
/* Maximum of 3 tries - WG7J */
if(count++ == 3)
return -1;
oldmode = sockmode(m->user,SOCK_ASCII);
tputs("login: ");
usflush(m->user);
if(mbxrecvline(m) == -1)
return -1;
if(*m->line == 4) /* Control-d */
return -1;
if(*m->line == '\0')
continue;
/* Chop off after name lenght */
m->line[MBXNAME] = '\0';
/* add a little test to avoid 'Mailfile busy' syndrome - WG7J
* Check for characters illegal in MS-DOS file names.
*/
for(cp = m->line;*cp != '\0';cp++)
if(dosfnchr(*cp) == 0)
break;
if(*cp != '\0')
continue;
strcpy(m->name,m->line);
tprintf("Password: %c%c%c",IAC,WILL,TN_ECHO);
usflush(m->user);
sockmode(m->user,SOCK_BINARY);
if(mbxrecvline(m) == -1)
return -1;
tprintf("%c%c%c",IAC,WONT,TN_ECHO);
sockmode(m->user,oldmode);
tputc('\n');
usflush(m->user);
/* This is needed if the password was send before the
* telnet no-echo options were receied. We neeed to
* flush the eold sequence from the input buffers, sigh
*/
if(socklen(m->user,0))/* discard any remaining input */
recv_mbuf(m->user,NULL,0,NULLCHAR,0);
if((m->privs = userlogin(m->name,m->line,&m->path,MBXLINE,
&anony,"tcpdef")) != -1){
if(anony)
log(m->user,"MBOX login: %s Password: %s",m->name,m->line);
else
log(m->user,"MBOX login: %s",m->name);
if(m->privs & EXCLUDED_CMD)
return -1;
#ifdef AX25
/*try to set the name as the user-call.
*this is a very crude test! Be careful...
*Login must have at leat 1 digit (0-9) in it,
*and it must be possible to convert it to a call.
*if this doesn't work, disallow the gateway command,
*no matter if this was allowed by priviledges or not.
*Be careful, some one with login name '4us' and
*permission set to allow gateway/netrom, will
*go out as '4us-15' or '4us-0' !!!!!
*11/15/91 WG7J/PA3DIS
*/
for(cp=m->name;*cp != '\0';cp++)
if(isdigit((int)*cp))
break;
if(*cp != '\0')
founddigit = 1;
if( (setcall(m->call,m->name) == -1) || (!founddigit) ) {
m->privs &= ~AX25_CMD;
m->privs &= ~NETROM_CMD;
}
#else
m->privs &= ~AX25_CMD;
m->privs &= ~NETROM_CMD;
#endif /* AX25 */
/* Set the morerows - WG7J */
m->morerows = 20;
return 0;
}
tputs("Login incorrect\n");
log(m->user,"MBOX Login failed: %s, pw %s",m->name,m->line);
#ifdef MAILERROR
mail_error("MBOX Login failed: %s, pw %s",m->name,m->line);
#endif
*m->name = '\0'; /* wipe any garbage */
}
}
return 0;
}
/* put up the prompt */
void
putprompt(m)
struct mbx *m;
{
char area[64];
char *cp1,*cp2;
#ifdef MAILCMDS
if(m->sid & MBX_SID)
tputs(">\n");
else {
#endif
if(m->sid & MBX_NRID)
tputs(Mbnrid);
#ifdef MAILCMDS
if(m->sid & MBX_AREA) {
cp1 = m->area;
cp2 = area;
/* Convert / and \ into . */
while(*cp1 != '\0') {
if(*cp1=='/')
*cp2 = '.';
else
*cp2 = *cp1;
cp1++;
cp2++;
}
*cp2 = '\0';
tprintf("Area: %s ",area);
}
#endif
if(m->sid & MBX_EXPERT)
tputs(">\n");
else {
#ifdef MAILCMDS
tprintf(MbCurrent,m->current);
#endif
if(MbShowAliases && AliasList) {
struct alias *a;
for(a=AliasList;a;a=a->next)
tprintf("%s,",a->name);
}
tputs(Mbmenu);
}
#ifdef MAILCMDS
}
#endif
}
/* Incoming mailbox session */
void
mbx_incom(s,t,p)
int s;
void *t;
void *p;
{
struct tipcb *tip;
struct mbx *m,*mp,*pp;
struct usock *up;
struct alias *a;
char *buf[3];
char tmp[AXBUF];
int rval;
FILE *fp;
int newpriv = 0;
/*
if((up = itop(s)) != NULLUSOCK)
if(up->iface->flags & NO_AX25)
*/
sockmode(s,SOCK_ASCII);
sockowner(s,Curproc); /* We own it now */
/* Secede from the parent's sockets, and use the network socket that
* was passed to us for both input and output. The reference
* count on this socket will still be 1; this allows the domboxbye()
* command to work by closing that socket with a single call.
* If we return, the socket will be closed automatically.
*/
close_s(Curproc->output);
close_s(Curproc->input);
Curproc->output = Curproc->input = s;
/* We'll do our own flushing right before we read input */
setflush(s,-1);
if((m = newmbx()) == NULLMBX){
tputs("Too many mailbox sessions\n");
return;
}
m->proc = Curproc;
m->user = s;
m->escape = 20; /* default escape character is Ctrl-T */
m->type = (t == NULL) ? TELNET_LINK : (int) t;
#ifdef TIPSERVER
#ifdef XMODEM
if(m->type == TIP_LINK) {
tip = (struct tipcb *) p;
tip->raw=0;
m->tip=tip;
}
#endif
#endif
/* discard any remaining input */
/*
while(socklen(s,0))
recv_mbuf(s,NULL,0,NULLCHAR,0);
*/
/* get the name of the remote station */
if(mbx_getname(m) == -1) {
exitbbs(m);
return;
}
Totallogins++;
log(s,"MBOX open");
#ifdef RLOGINSERVER
if(m->type == RLOGIN_LINK) {
m->state = MBX_CMD; /* start in command state */
tputc ('\n');
dosysop (1, (char **)0, (void *)m);
log(m->user, "MBOX exit: %s", m->name); /* N5KNX: log exits */
exitbbs(m);
return;
}
#endif
if(m->privs & IS_BBS)
m->sid |= MBX_SID; /*force bbs status*/
else if(m->privs & IS_EXPERT)
m->sid |= MBX_EXPERT;
loguser(m);
m->state = MBX_CMD; /* start in command state */
#ifdef MAILCMDS
tputs(MboxId);
#endif
/* Say 'hello' only if user is not a bbs - WG7J */
#ifdef MAILCMDS
if(!(m->sid & MBX_SID+MBX_EXPERT)) {
#endif
#ifdef USERLOG
tprintf(Mbwelcome,m->username ? m->username : m->name);
#else
tprintf(Mbwelcome,m->name);
#endif
#if defined AX25 || defined NETROM
if(m->family == AF_INET)
#endif
tprintf(Mbbanner,Hostname,Version);
#if defined AX25 || defined NETROM
else
tprintf(Mbbanner,pax25(tmp,Mycall),Version);
#endif
/* How many users are there currently ? */
tprintf(CurUsers,BbsUsers,BbsUsers == 1 ? "" : "s");
#ifdef MAILCMDS
/* Do we accept third party mail ? */
if(!ThirdParty)
tputs(Mbwarning);
#endif
tputc('\n');
/* Is there a message of the day ? */
if((fp = fopen(Motdfile,READ_TEXT)) != NULLFILE) {
sendfile(fp,m->user,ASCII_TYPE,0, m);
fclose(fp);
}
#ifdef MAILCMDS
}
if(!(m->sid & MBX_SID)) {
/* Enable our local message area,
* only if we're not a bbs - WG7J
*/
buf[1] = m->name;
doarea(2,buf,m);
#ifdef USERLOG
/* Tell about new arrived mail in message areas - WG7J */
if(Mbnewmail)
listnewmail(m,1);
#ifdef REGISTER
/* See if the username is empty. If so, the user hasn't
* registerd yet, so we need to beep and remind.
*/
if(MbRegister && !m->username)
tprintf("\n\007Please type 'REGISTER' at the > prompt.\n");
#endif /* REGISTER */
#endif /* USERLOG */
}
#endif /* MAILCMDS */
/* Send prompt */
putprompt(m);
/* now get commands */
while(mbxrecvline(m) != -1){
#ifdef MAILCMDS
/* Only tell about new mail when in our own area - WG7J */
if(!(m->sid & MBX_SID)){
if(isnewprivmail(m) > 0L)
newpriv = 1;
else
newpriv = 0;
/* Do not check mailfile if we're bbs - WG7J*/
scanmail(m);
}
#endif
/* check for an alias - WG7J */
if((a=findalias(m->line)) != NULL)
strcpy(m->line,a->cmd);
if((rval = mbx_parse(m)) == -2)
break;
if(rval == 1)
tputs("Bad syntax.\n");
#ifdef MAILCMDS
if(newpriv) {
tputs("You have new mail. ");
if(m->areatype != PRIVATE)
tprintf("Change area with 'A %s'. ", m->name);
tputs("Please Kill when read!\n");
}
#endif
putprompt(m);
m->state = MBX_CMD;
}
log(m->user, "MBOX exit: %s", m->name); /* N5KNX: log exits */
exitbbs(m);
}
void
exitbbs(m)
struct mbx *m;
{
struct mbx *mp,*pp;
struct usock *up;
/* Moving the socket close call to here
* will send a disconnect to the user before cleaning up
* the user's data structure. This gives a faster response perception
* to the user - WG7J
* N5KNX: but we must be careful to reset Curproc->{input,output} since
* otherwise killproc() will try again to close these sockets, and by
* then some other process may own it. This sure is a kludge!
*/
close_s(Curproc->output);
if (itop(Curproc->output) == NULLUSOCK) {
if (Curproc->input == Curproc->output) Curproc->input = -1;
Curproc->output = -1;
}
#ifdef MAILCMDS
closenotes(m);
free(m->to);
free(m->tofrom);
free(m->origto);
free(m->origbbs);
free(m->subject);
free(m->date);
free(m->tomsgid);
#endif
free(m->path);
free(m->startmsg);
#ifdef USERLOG
free(m->username);
free(m->IPemail);
free(m->homebbs);
#endif
#ifdef MAILCMDS
/* Close the tempfiles if they are not nullpointers - WG7J */
if(m->tfile != (FILE *) 0)
fclose(m->tfile);
if(m->tfp != (FILE *) 0)
fclose(m->tfp);
if(m->mfile != (FILE *) 0)
fclose(m->mfile);
if(m->stdinbuf != NULLCHAR)
free(m->stdinbuf);
if(m->stdoutbuf != NULLCHAR)
free(m->stdoutbuf);
free((char *)m->mbox);
#endif
/* now free it from list */
for(mp=Mbox,pp=NULLMBX;mp && mp!=m;pp=mp,mp=mp->next);
if(!mp)
/* what happened ??? */
return;
if(pp==NULLMBX) /* first one on list */
Mbox = Mbox->next;
else
pp->next = m->next;
free((char *)m);
BbsUsers--;
}
/**********************************************************************/
static struct cmds DFAR Mbcmds[] = {
#ifdef MAILCMDS
"", doreadnext, 0, 0, NULLCHAR,
#endif
"?", dombhelp, 0, 0, NULLCHAR,
#ifdef MAILCMDS
"area", doarea, 0, 0, NULLCHAR,
#endif
"alias", dombalias, 0, 0, NULLCHAR,
"bye", domboxbye, 0, 0, NULLCHAR,
#ifdef GATECMDS
#if defined AX25 || defined NETROM
"connect", dombconnect,0, 0, NULLCHAR,
#endif
#endif
#ifdef CONVERS
"convers", dombconvers,0, 0, NULLCHAR,
#endif
#ifdef FILECMDS
#ifdef XMODEM
"download", dodownload, 0, 2, "D[U|X] <filename>",
#else
"download", dodownload, 0, 2, "D[U] <filename>",
#endif
#endif
#ifdef GATECMDS
"escape", dombescape, 0, 0, NULLCHAR,
#endif
#ifdef FOQ_CMDS
"finger", dombfinger, 0, 0, NULLCHAR,
#endif
"help", dombhelp, 0, 0, NULLCHAR,
"info", dombhelp, 0, 0, NULLCHAR,
"iheard", dombipheard,0, 0, NULLCHAR,
"iproute", dombiproute,0, 0, NULLCHAR,
#ifdef AX25
"jheard", dombjheard, 0, 0, NULLCHAR,
#endif
#ifdef MAILCMDS
"kill", dodelmsg, 0, 0, NULLCHAR,
"list", dolistnotes,0, 0, NULLCHAR,
#endif
"mboxuser", dombusers, 0, 0, NULLCHAR,
#if defined GATECMDS && defined NETROM
"nodes", dombnrnodes,0, 0, NULLCHAR,
"nroutes", dombnrneighbour, 0, 0, NULLCHAR,
#endif
#if defined FOQ_CMDS && defined TTYLINKSERVER
"operator", dochat, 0, 0, NULLCHAR,
#endif
#if defined GATECMDS && defined AX25
"ports", dombports, 0, 0, NULLCHAR,
#endif
#ifdef GATECMDS
"ping", dombping, 0, 2, "PI <host> [<len>] [<timeout>]",
#endif
#if defined FOQ_CMDS && defined CALLCLI
"query", dombcallbook, 0, 2, "Q callsign\nMultiple callsigns allowed per line",
#endif
#ifdef MAILCMDS
"read", doreadmsg, 0, 0, NULLCHAR,
"send", dosend, 0, 0, NULLCHAR,
#if defined USERLOG && defined REGISTER
"register", doregister, 0, 0, NULLCHAR,
#endif
#endif
#ifdef GATECMDS
"telnet", dombtelnet, 0, 2, "T hostname",
#endif
#ifdef FILECMDS
#ifdef XMODEM
"upload", dombupload, 0, 2, "U[U|X] <filename>",
#else
"upload", dombupload, 0, 2, "U[U] <filename>",
#endif
#endif
#ifdef MAILCMDS
"verbose", doreadmsg, 0, 0, NULLCHAR,
#endif
#ifdef FILECMDS
"what", dowhat, 0, 0, NULLCHAR,
#endif
"xpert", dombexpert, 0, 0, NULLCHAR,
#ifdef FILECMDS
"zap", dozap, 0, 2, "Z filename",
#endif
#ifdef MAILCMDS
"[", dosid, 0, 0, NULLCHAR,
#ifdef MBFWD
"f>", dorevfwd, 0, 0, NULLCHAR,
#endif
#endif
"@", dosysop, 0, 0, NULLCHAR,
"***", dostars, 0, 0, NULLCHAR,
";", dombsemicolon, 0, 0, NULLCHAR,
NULLCHAR, NULLFP, 0, 0, "Huh?",
};
/* "twocmds" defines the MBL/RLI two-letter commands, eg. "SB", "SP" and so on.
* They have to be treated specially since cmdparse() wants a space between
* the actual command and its arguments.
* "SP FOO" is converted to "s foo" and the second command letter is saved
* in m->stype. Longer commands like "SEND" are unaffected, except for
* commands starting with "[", i.e. the SID, since we don't know what it will
* look like.
*/
static char twocmds[] =
#ifdef MAILCMDS
"aklrsv"
#endif
#ifdef FILECMDS
"du"
#endif
"[mx";
int
mbx_parse(m)
struct mbx *m;
{
char *cp;
int i;
char *newargv[2];
/* Translate entire buffer to lower case */
for (cp = m->line; *cp != '\0'; ++cp)
if(isupper(*cp))
*cp = tolower(*cp);
/* Skip any spaces at the begining */
for(cp = m->line;isspace(*cp);++cp)
;
m->stype = ' ';
if(*cp != '\0' && *(cp+1) != '\0') {
for(i=0; i<strlen(twocmds); ++i){
if(*cp == twocmds[i] && (isspace(*(cp+2)) || *(cp+2) == '\0'
|| *cp == '[')){
if(islower(*(++cp)))
m->stype = toupper(*cp); /* Save the second character */
else
m->stype = *cp;
*cp = ' ';
break;
}
}
}
#ifdef MAILCMDS
/* See if the input line consists solely of digits */
cp = m->line;
for(cp = m->line;isspace(*cp);++cp)
;
newargv[1] = cp;
for(;*cp != '\0' && isdigit(*cp);++cp)
;
if(*cp == '\0' && strlen(newargv[1]) > 0) {
newargv[0] = "r";
return doreadmsg(2,newargv,(void *)m);
} else
#endif
return cmdparse(Mbcmds,m->line,(void *)m);
}
/* This works like recvline(), but telnet options are answered and the
* terminating newline character is not put into the buffer. If the
* incoming character equals the value of escape, any queued input is
* flushed and -2 returned.
*
* mbxrecvline() now can gobble up suboptions - 94/02/14 VE4WTS
*/
int
mbxrecvline(m)
struct mbx *m;
{
int s = m->user;
int escape = m->escape;
char *buf = m->line;
int c, cnt = 0, opt,cl;
if(buf == NULLCHAR)
return 0;
usflush(Curproc->output);
alarm(Mbtdiscinit*1000L); /* Start inactivity timeout - WG7J */
while((c = recvchar(s)) != EOF){
alarm(0L);
if(c == IAC){ /* Telnet command escape */
if((c = recvchar(s)) == EOF)
break;
if(c >= 250 && c < 255 && (opt = recvchar(s)) != EOF){
switch(c){
case SB:
opt=recvchar(s); /* Get the real option */
if(opt==EOF)
break;
cl=opt;
c=recvchar(s);
/* Gobble up until we see IAC SE */
while((c!=EOF) && !(cl==IAC && c==SE)){
/* maybe check for timeout here, in case someone
happened to send a binary file with the IAC SB
sequence in it. */
cl=c; /* keep track of second last char read */
c=recvchar(s);
}
/* and tell the client where to go... */
/* tprintf("%c%c%c",IAC,WONT,opt); */
break;
case WILL:
if(opt==TN_LINEMODE){
/* we WANT linemode */
tprintf("%c%c%c",IAC,DO,opt);
/* Tell client to do editing */
tprintf("%c%c%c%c%c%c%c",IAC,SB,TN_LINEMODE,1,1,IAC,SE);
} else
tprintf("%c%c%c",IAC,DONT,opt);
break;
case WONT:
tprintf("%c%c%c",IAC,DONT,opt);
break;
case DO:
tprintf("%c%c%c",IAC,WONT,opt);
break;
case DONT:
tprintf("%c%c%c",IAC,WONT,opt);
}
/* to be fixed usflush(Curproc->output);*/
continue;
}
if(c != IAC && (c = recvchar(s)) == EOF)
break;
}
/* ordinary character */
if(c == '\r' || c == '\n')
break;
if(uchar(c) == escape){
if(socklen(s,0)) /* discard any remaining input */
recv_mbuf(s,NULL,0,NULLCHAR,0);
cnt = -2;
break;
}
/* Handle <del> chars - from wa7tas */
if(c == 8 && cnt > 0) {
*--buf = 0;
cnt--;
} else {
*buf++ = c;
++cnt;
}
if(cnt == MBXLINE - 1)
break;
alarm(Mbtdiscinit*1000L); /* Restart inactivity timeout - WG7J */
}
if(c == EOF && cnt == 0)
return -1;
*buf = '\0';
return cnt;
}
/* New forwarding option, simply ignore all data - WG7J */
int
dombsemicolon(int argc,char *argv[],void *p) {
return 0;
}
/* Determine what type of prompt is optimal, ie, can we read just one char? */
int
charmode_ok(m)
struct mbx *m;
{
if (m->type == TELNET_LINK || m->type == TIP_LINK) {
#ifdef notdef
if ((up=itop(m->proc->output)) != NULLSOCK && up->type == TYPE_TCP) {
up->cb.tcb->??? can't get to telnet->session->ttystate.echo
}
#endif
if (!(m->sid & MBX_LINEMODE)) return 1; /* char mode OK (see XP cmd) */
}
return 0;
}
int
domboxbye(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
m = (struct mbx *)p;
/* for bbs's, just disconnect */
if(m->sid & MBX_SID)
return -2;
#ifdef USERLOG
#ifdef MAILCMDS
setlastread(m);
#endif
updatedefaults(m);
#endif
/* Now say goodbye */
if(!(m->privs & MBX_EXPERT))
tprintf("\nThank you %s,\nfor calling %s JNOS.\n\n",
#ifdef USERLOG
m->username ? m->username : m->name,
#else
m->name,
#endif
Hostname);
#ifdef TIPSERVER
if(m->type == TIP_LINK)
tputs("Please hang up now.\n");
#endif
usflush(m->user);
return -2; /* signal that exitbbs() should be called */
}
static int
dombhelp(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char buf[FILE_PATH_SIZE];
int i;
FILE *fp;
struct mbx *m = (struct mbx *)p;
if(*argv[0] == '?') {
if(MbShowAliases && AliasList) {
struct alias *a;
tputs("Aliases:");
for(a=AliasList;a;a=a->next)
tprintf(" %s",a->name);
tputc('\n');
}
sprintf(buf,"%s/longmenu.eng",Helpdir);
if((fp = fopen(buf,READ_TEXT)) != NULLFILE) {
sendfile(fp,Curproc->output,ASCII_TYPE,0,m);
fclose(fp);
} else {
tputs("No menu available.\n");
}
return 0;
}
buf[0] = '\0';
if(argc > 1)
for(i=0; Mbcmds[i].name != NULLCHAR; ++i)
if(!strncmp(Mbcmds[i].name,argv[1],strlen(argv[1]))) {
sprintf(buf,"%s/%s.hlp",Helpdir,Mbcmds[i].name);
break;
}
if(buf[0] == '\0')
if(*argv[0] == 'i') {
/* INFO command */
tprintf(Nosversion,Version);
sprintf(buf,"%s/info.hlp",Helpdir);
} else
sprintf(buf,"%s/help.hlp",Helpdir);
if((fp = fopen(buf,READ_TEXT)) != NULLFILE) {
sendfile(fp,Curproc->output,ASCII_TYPE,0,m);
fclose(fp);
} else {
if(*argv[0]!='i')
tputs("No help available.\n");
}
return 0;
}
extern void dumproute __ARGS((struct route *rp,char *p));
extern char RouteHeader[];
/* Show non-private routes only */
int
dombiproute(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int i,bits;
struct route *rp;
struct mbx *m = (struct mbx *)p;
char buf[85];
if(m->privs & NO_LISTS) {
tputs(Noperm);
return 0;
}
tputs(RouteHeader);
for(bits=31;bits>=0;bits--){
for(i=0;i<HASHMOD;i++){
for(rp = Routes[bits][i];rp != NULLROUTE;rp = rp->next){
if(!(rp->flags & RTPRIVATE)) {
dumproute(rp,buf);
if(tprintf("%s\n",&buf[4]) == EOF)
return 0;
}
}
}
}
if(R_default.iface != NULLIF && !(R_default.flags & RTPRIVATE)) {
dumproute(&R_default,buf);
if(tprintf("%s\n",&buf[4]) == EOF)
return 0;
}
return 0;
}
static int
dombexpert(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
m = (struct mbx *)p;
switch(m->stype) {
case 'M':
if(argc == 1)
tprintf("-more- after %d lines\n",m->morerows);
else {
m->morerows = atoi(argv[1]);
}
break;
case 'A':
m->sid ^= MBX_AREA;
break;
case 'N':
m->sid ^= MBX_NRID;
break;
case 'P':
m->sid ^= MBX_LINEMODE;
tprintf("LINEMODE is now %sabled\n", m->sid&MBX_LINEMODE ? "en" : "dis");
break;
#if defined USERLOG && defined REGISTER
case 'R':
if(argc > 1) {
/* Change the state of the 'Reply-to' header */
if(!stricmp(argv[1],"on"))
m->sid |= MBX_REPLYADDR;
else if(!stricmp(argv[1],"off"))
m->sid &= ~MBX_REPLYADDR;
}
tprintf("'Reply-to: %s' header is %sadded when sending mail.\n",
( m->IPemail ?
((m->sid & MBX_REPLYADDR) ? m->IPemail : "") :
"" ),
(m->sid & MBX_REPLYADDR) ? "" : "not " );
if((m->sid & MBX_REPLYADDR) && !m->IPemail)
tprintf("Please 'register' to set your email reply-to address!\n");
break;
#endif
default:
m->sid ^= MBX_EXPERT;
break;
}
return 0;
}
#if defined FOQ_CMDS && defined TTYLINKSERVER
extern char SysopBusy[];
static int
dochat(argc,argv,p)
int argc;
char *argv[];
void *p;
{
char buf[8], *newargv[3];
struct mbx *m;
m = (struct mbx *)p;
if (MAttended) {
m->state = MBX_CHAT;
newargv[0] = "C";
newargv[1] = Hostname;
sprintf(buf,"%d",IPPORT_TTYLINK);
newargv[2] = buf;
m->startmsg = mallocw(50);
sprintf(m->startmsg,"*** MBOX Chat with %s\n",m->name);
return dombtelnet(3,newargv,p);
} else {
tputs(SysopBusy);
}
/* It returns only after a disconnect or refusal */
return 0;
}
#endif /* TTYLINKSERVER */
static int
dombipheard(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m = (struct mbx *)p;
if(m->privs & NO_LISTS) {
tputs(Noperm);
return 0;
}
return doipheard(argc,argv,NULL);
}
#ifdef AX25
static int
dombjheard(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct iface *ifp;
struct mbx *m = (struct mbx *)p;
if(m->privs & NO_LISTS) {
tputs(Noperm);
return 0;
}
if(argc > 1){
if( ((ifp = if_lookup(argv[1])) == NULLIF) || (ifp->type != CL_AX25) ||
((ifp->flags & HIDE_PORT) && !(m->privs & MBX_SYSOP)) ) {
tprintf(Badinterface,argv[1]);
return 0;
}
axheard(ifp);
return 0;
}
for(ifp = Ifaces;ifp != NULLIF;ifp = ifp->next){
if((ifp->flags & LOG_AXHEARD) && ( !(ifp->flags & HIDE_PORT) || m->privs&MBX_SYSOP) )
if(axheard(ifp) == EOF)
break;
}
return 0;
}
#endif
#if defined FOQ_CMDS && defined CALLCLI
static int
dombcallbook(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char buf[8], *newargv[3];
extern char *Callserver;
int req, ret = 0;
m = (struct mbx *) p;
sprintf(buf,"%d",IPPORT_CALLDB);
newargv[0] = "Q";
newargv[1] = Callserver;
newargv[2] = buf;
for (req = 1; req < argc; req++) {
if(argv[req] == NULLCHAR)
return ret;
m->startmsg = mallocw(80); /* is freed each time by gw_connect() */
sprintf(m->startmsg,"%s\n", argv[req]);
log(m->user, "MBOX callbook %s: %s",m->name,argv[req]);
tprintf("Looking for \" %s \" in the callbook at %s\n",argv[req],Callserver);
ret = dombtelnet(3,newargv,p);
}
return ret; /* It looks like all possible returns are zero anyway! */
}
#endif /* CALLCLI */
/*Password protection added - 920118, WG7J */
int
dosysop(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
int c;
int len,pwdc[5],i,valid=0;
char *cp;
extern struct cmds DFAR Cmds[];
m = (struct mbx *) p;
log(m->user,"MBOX: %s attempting SYSOP",m->name);
/*If you want anyone with the password to go sysop-mode
*comment out the next 4 line ! -WG7J
*/
if(!(m->privs & SYSOP_CMD)){
tputs(Noperm);
#ifdef MAILERROR
mail_error("%s: SYSOP denied!\n",m->name);
#endif
return 0;
}
/*only if set,
*check for the password before letting users proceed
*/
m->state = MBX_SYSOPTRY;
if((len = strlen(Mbpasswd)) != 0) {;
for (i=0;i<5;i++)
tprintf("%d ",(pwdc[i]=RANDOM(len))); /*print the random chars*/
tputc('\n');
while(1) {
c = mbxrecvline(m);
if(c == EOF || c == -2)
return 0;
if(*m->line == '\0')
break;
cp = m->line;
for(i=0;i<5;i++)
if(*cp++ != Mbpasswd[pwdc[i]])
break;
if (i == 5)
valid = 1;
}
if(!valid)
return 0;
}
log(m->user,"MBOX: %s is now SYSOP",m->name);
m->state = MBX_SYSOP;
tputs("\n\aType 'exit' to return\n");
for(;;){
tprintf("%lu Jnos> ",coreleft());
usflush(Curproc->output);
if(mbxrecvline(m) < 0)
break;
log(m->user,"MBOX sysop: %s",m->line);
if(cmdparse(Cmds,m->line,NULL) == -2)
break;
}
return 0;
}
/* Handle the "*** Done" command when reverse forwarding ends or the
* "*** LINKED to" command.
*/
int
dostars(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
int anony = 1;
int founddigit = 0;
long oldprivs;
char *cp;
m = (struct mbx *)p;
/* Allow 'linked to' from anyone, but reset SYSOP priviledges
* when the sysop-password is not set !
* Also try to set the new call !
* Inspired by Kurt, wb5bbw
* Check for the strange TEXNET linked message !
* 920220 - WG7J
*/
if((argc >= 4) && !strcmp(argv[1],"linked") && !strcmp(argv[2],"to")) {
if(m->privs & NO_LINKEDTO) {
puts(Noperm);
#ifdef GWTRACE
log(m->user,"MBOX LINKED: %s permission denied",m->name);
#endif
return 0;
}
#ifdef GWTRACE
log(m->user,"MBOX LINKED: %s changed to %s",m->name,argv[3]);
#endif
#ifdef USERLOG
#ifdef MAILCMDS
setlastread(m);
#endif
updatedefaults(m);
#endif
strcpy(m->name,argv[3]);
oldprivs = m->privs; /*Save this !*/
/* Try to find the privileges of this user from the userfile */
if((m->privs = userlogin(m->name,NULLCHAR,&m->path,MBXLINE,
&anony,"")) == -1)
if((m->privs = userlogin("bbs",NULLCHAR,&m->path,
MBXLINE,&anony,"")) == -1)
if((m->privs = userlogin("anonymous",NULLCHAR,
&m->path,MBXLINE,&anony,"")) == -1){
m->privs = 0;
free(m->path);
m->path = NULLCHAR;
}
if(m->privs & EXCLUDED_CMD)
return domboxbye(0,NULLCHARP,p);
#ifdef AX25
/* Set the call */
for(cp=m->name;*cp != '\0';cp++)
if(isdigit((int)*cp))
break;
if(*cp != '\0')
founddigit = 1;
if( (setcall(m->call,m->name) == -1) || (!founddigit) ) {
m->privs &= ~AX25_CMD;
m->privs &= ~NETROM_CMD;
}
#else
m->privs &= ~AX25_CMD;
m->privs &= ~NETROM_CMD;
#endif
/*Kill ssid in name, if any*/
if((cp=strchr(m->name,'-')) != NULLCHAR)
*cp = '\0';
/* Check if sysop password is set,
* if not, disallow sysop privs no matter what !
*/
if(*Mbpasswd == '\0')
m->privs &= ~SYSOP_CMD;
/* Check to see if any of NO_READ,NO_SEND or NO_3PARTY were set,
* if so, dis-allow those no matter what
* (so that users cannot get priviledges by issuing a ***linked)
* 920220 - WG7J
*/
if(oldprivs & NO_SENDCMD)
m->privs |= NO_SENDCMD;
if(oldprivs & NO_READCMD)
m->privs |= NO_READCMD;
if(oldprivs & NO_3PARTY)
m->privs |= NO_3PARTY;
if(oldprivs & NO_CONVERS)
m->privs |= NO_CONVERS;
if(oldprivs & NO_LISTS)
m->privs |= NO_LISTS;
/* Log this new user in */
loguser(m);
#ifdef USERLOG
tprintf("Oh, hello %s.\n",m->username ? m->username : m->name);
#else
tprintf("Oh, hello %s.\n",m->name);
#endif
#ifdef MAILCMDS
changearea(m,m->name);
#endif
return 0;
}
if(argc > 1 && (m->sid & MBX_SID)) /* "*** Done" or similar */
return -2;
return -1;
}
#ifdef FOQ_CMDS
int
dombfinger(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m;
char *host, *user = NULLCHAR, buf[8], *newargv[3];
if(argc > 2){
tputs("Usage: F user@host or F @host or F user.\n");
return 0;
}
host = Hostname;
if(argc == 2){
if((host = strchr(argv[1], '@')) != NULLCHAR){
*host = '\0';
host++;
} else
host = Hostname;
user = argv[1];
}
m = (struct mbx *) p;
m->startmsg = mallocw(80);
if(user != NULLCHAR)
sprintf(m->startmsg,"%s\n",user);
else
strcpy(m->startmsg,"\n");
newargv[0] = "";
newargv[1] = host;
sprintf(buf,"%d",IPPORT_FINGER);
newargv[2] = buf;
return dombtelnet(3,newargv,p);
}
#endif /* FOQ_CMDS */
#ifdef CONVERS
extern int Mbconverse;
extern int CDefaultChannel;
int
dombconvers(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct mbx *m = (struct mbx *)p;
int channel = 0;
if(m->privs & NO_CONVERS) {
tputs(Noperm);
#ifdef MAILERROR
mail_error("%s: converse denied\n",m->name);
#endif
return 0;
}
if(!Mbconverse) {
tputs("Mailbox Convers server not enabled\n");
return 0;
}
m->state = MBX_CONVERS;
if(argc > 1)
channel = atoi(argv[1]);
else
channel = CDefaultChannel;
#ifdef GWTRACE
log(m->user,"MBOX CONVERS: %s",m->name);
#endif
mbox_converse(m,channel);
return 0;
}
#endif /* CONVERS */
#endif /* MAILBOX */